/**
 * Copyright (c) 2009 blurredVision
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
 * associated documentation files (the "Software"), to deal in the Software without restriction, 
 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or 
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 
 * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 
 * OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#ifndef __MODEL_MESH_H__
#define __MODEL_MESH_H__

#pragma once

#include "geom/Matrix.h"

#include "ITexture.h"
#include "IRenderer.h"

#include "BoundingSphere.h"
#include "IMeshGeometry.h"
#include "IModelBaseRenderer.h"

#include "sg/SceneNode.h"
#include "IShaderEffect.h"

namespace model {

class IModelBase;
struct sComplexMaterial;

struct sEffectData {
	SHADERHANDLE handle;		///< The handle of the effect parameter
	eEffectDataType dataType;	///< The data type
	unsigned int numElements;
	void* data;
};

enum eMeshType {
	MT_UNKNOWN = 0,
	MT_NORMAL,
	MT_DUMMY,
	MT_BOUNDS,
};

/**
 *	KeyFrame informations
 */ 
struct KeyFrame {
	int           frame;
	math::Matrix4 matrix;
};

struct KeyFrameInfo {
	int numFrames;					///< The number of keyframes stored for that object
	std::vector<KeyFrame> frames;	///< The list of stored keyframes
	math::Matrix4 currentMat;		///< The current transformation matrix
};

/**
 * \ingroup CoreEngine
 *
 * The IMesh class.<br>
 * Stores the vertex data for a single mesh.<br>
 * An IModelBase can store multiple IMesh instances.
 * The actual geometry data is stored in the IMeshGeometry interface.
 *
 * \date 04-01-2007
 *
 * \author juckel
 *
 */
class DLL_EXPORT IMesh 
	: public sg::SceneNode
{
public:
	IMesh(void);

	 /// Loads a IMesh objects and it's data from a file 
	bool load(FILE *file);

	bool operator<(const IMesh& rhs)const;
	bool operator>(const IMesh& rhs)const;

	virtual void drawMesh(math::Matrix4 *postMat);
	/// Draws an IMesh object
	virtual void drawNodes(bool drawTransparent = false, math::Matrix4 *postMat = 0);

	/// Update the scene node
	virtual void update(double dt);

	/// Returns the complex material associated with this IMesh
	sComplexMaterial getMaterial();
	
	/// Assign a material. The material will be stored inside the IModelBase class and a reference will be set.
	void setMaterial(const sComplexMaterial &material, bool transparent);

	/// Sets the name of the object, so IModelBase knows it's children
	void setName(const std::string &name);

	/// Returns the name of the mesh
	const std::string& getName() const;

	/// Disables the standard shader associated with the object. 
	/// By default the default.fx shader is loaded and used.
	void setEnableShader(bool value);

	/// Indicates if a shader is enabled
	const bool isShaderEnabled() const;

	/// Returns the actual mesh geometry
	IMeshGeometry* getMeshGeometry() const;

	virtual std::string getClassType() const { return "IMesh"; }

	// Returns true, if the mesh is visible ( false if it is a bounding box)
	const bool isMeshVisible() const;
	const bool isBoundingVolume() const;

	bool addShaderInput(eEffectDataType datatype, const std::string &identifier, void *data, int size);

	static unsigned int GetMeshCount();

	virtual void updateVisiblity(Frustum *frustum);

	/** Altjohann
	*	Tests if a mesh has its center in (0,0,0)
	*	\return bool
	*/
	bool isCentered();

	/// Set the texture atlas information. If 
	void setTextureAtlasInfo( int texNum, const math::Vector4 &values);

	/// Sets the transparency to the specified value. This must be done before adding it to a model
	void setTransparent(bool value);

	const bool isTransparent() const;

	void setCamDistanceSqr(float distance = 0);

	void setKeyFrameInfo(const KeyFrameInfo &info);

	void updateKeyFrame(double frameFrac);

protected:
	virtual ~IMesh(void);
	void setCustomVariables();

	/// Performs a raw copy of data of an instance of the IMesh object.
	virtual sg::SceneNode* rawcopy();

	void calculateMinMax( math::Vector3 &minVec, math::Vector3 &maxVec);
	void calculateBoundingSphere();

	static IRenderer *s_pRenderer;

	bool             m_bUseShaderEffect;
	IMeshGeometry   *m_pGeometry;
	std::string      m_sName;
	bool             m_bMeshVisible;		///< Indicates if a submesh is visible (not related to the SceneNode's updateVisibility
	bool             m_bBoundingVol;
	bool             m_bTransparent;

	sComplexMaterial         m_pMaterial;	///< A pointer to the complex material
	std::vector<sEffectData> m_lEffectData;	///< Some custom variables that can be stored inside the mesh for a standard complex material

	math::Vector4 m_vTextureAtlasDiffuse;	///< Definition for the texture atlas. x,y define the offset, z,w define the scale of the texture coordinates
	math::Vector4 m_vTextureAtlasNormal;
	math::Vector4 m_vTextureAtlasRefl;

	bool m_bTAHandlesInitialized;
	SHADERHANDLE  hTADiffuse;
	SHADERHANDLE  hTANormal;
	SHADERHANDLE  hTARefl;

	static unsigned int s_uiNumMeshes;

	static ICamera* s_pCam;
	unsigned int m_uiLOD;

	KeyFrameInfo m_KeyFrameInfo;

	math::Matrix4 m_mWorldTransform;
};

} // namespace

#endif
